/** 事件派发器 */
export default class EventDispatcher<IEventDef> {

    private _callbackMap: Map<keyof IEventDef, Map<any, Set<(data: IEventDef[keyof IEventDef]) => any>>> = new Map()
    private _onceCallbackMap: Map<keyof IEventDef, Map<any, Set<(data: IEventDef[keyof IEventDef]) => any>>> = new Map()

    /** 发送事件 */
    send<EventType extends keyof IEventDef>(type: EventType, data: IEventDef[EventType]) {

        this._callbackMap.get(type)?.forEach((cbSet, caller) => {
            cbSet.forEach(cb => {
                cb.call(caller, data)
            })
        })
        //单次回调 触发完取消监听
        let cbMap = this._onceCallbackMap.get(type)
        if (cbMap) {
            cbMap.forEach((cbSet, caller) => {
                cbSet.forEach(cb => {
                    cb.call(caller, data)
                })
            })
            this._onceCallbackMap.delete(type)
        }
    }

    /** 监听事件 */
    on<EventType extends keyof IEventDef>(type: EventType, caller: any, callback: (data: IEventDef[EventType]) => any) {
        let cbMap = this._callbackMap.get(type)
        !cbMap && this._callbackMap.set(type, cbMap = new Map())
        let cbSet = cbMap.get(caller)
        !cbSet && cbMap.set(caller, cbSet = new Set())
        cbSet.add(callback)
    }

    /** 监听事件 只触发一次 */
    once<EventType extends keyof IEventDef>(type: EventType, caller: any, callback: (data: IEventDef[EventType]) => any) {
        let cbMap = this._onceCallbackMap.get(type)
        !cbMap && this._onceCallbackMap.set(type, cbMap = new Map())
        let cbSet = cbMap.get(caller)
        !cbSet && cbMap.set(caller, cbSet = new Set())
        cbSet.add(callback)
    }

    /** 取消监听事件 */
    off<EventType extends keyof IEventDef>(type: EventType, caller: any, callback: (data: IEventDef[EventType]) => any) {
        let cbMap = this._callbackMap.get(type)
        if (cbMap) {
            let cbSet = cbMap.get(caller)
            if (cbSet) {
                cbSet.delete(callback)
                if (!cbSet.size) {
                    cbMap.delete(caller)
                    if (!cbMap.size) {
                        this._callbackMap.delete(type)
                    }
                }
            }
        }
    }

    /** 取消监听所有事件  */
    offAll(caller: any) {
        this._callbackMap.forEach(cbMap => cbMap.delete(caller))
    }
}